package com.hy.parse;

import com.hy.entity.Entity;
import com.hy.enums.Dialect;
import com.hy.jdbc.Database;
import com.hy.jdbc.impl.AbstractDatabase;
import com.hy.main;
import com.hy.util.ClassUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: huangya
 * @Date: 2020/5/21
 * @Description:
 */
public class DomParser {

    private static final String SEPARATOR = "/";

    private static final String IS_ALL_TABLE = "isAllTable";

    private static final String CONNECTION = "connection";

    private static final String ENTRY = "entry";

    private static final String URL = "url";

//    private static final String DRIVER_CLASS = "driverClass";
//
//    private static final String DIALECT = "dialect";

    private static final String DATABASE = "database";

    private static final String TABLE = "table";

    private static final String TABLE_NAME = "tableName";

    private static final String CLASS_NAME = "className";

    private static final String DESCRIBE = "describe";

    private static final String INJECT_CLASS_NAME = "injectClassName";

    private static final String RESTFUL_CLASS_URL = "restfulClassUrl";

    private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();


    public static List<Map<String, Object>> parseXml(){
        File file = new File(ClassUtils.getClassPath());
        File[] files = file.listFiles();
        return parseXml(files);
    }

    public static List<Map<String, Object>> parseXml(File... files){
        List<Map<String, Object>> allXmlsList = new ArrayList<>();
        List<Map<String, Object>> xmlMapList;
        for(File file : files){
            //只读取以".xml"结尾的文件
            if(file.isFile() && file.getAbsolutePath().endsWith(".xml")){
                xmlMapList = doParseXml(file);
                allXmlsList.addAll(xmlMapList);
            }
        }
        return allXmlsList;
    }

    /**
     * 解析xml文件（可优化）
     * @param file
     */
    public static List<Map<String, Object>> doParseXml(File file){
        List<Map<String, Object>> tables = new ArrayList();
        Map<String, String> xmlMap = new HashMap<>();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(file);

            NodeList connectionNodeList = doc.getElementsByTagName(CONNECTION);
            for(int i=0;i<connectionNodeList.getLength();i++){
                Node node = connectionNodeList.item(i);
                if(node.getNodeType()==Node.ELEMENT_NODE){
                    //如果元素名为connection
                    if(DomParser.CONNECTION.equals(node.getNodeName())){
                        NamedNodeMap namedNodeMap = node.getAttributes();
                        for(int j=0;j<namedNodeMap.getLength();j++){
                            Node attr = namedNodeMap.item(j);
                            if(URL.equals(attr.getNodeName())){
                                String urlValue = attr.getNodeValue();
                                String database;
                                if(urlValue.contains("?")){
                                    database = urlValue.substring(urlValue.lastIndexOf('/')+1, urlValue.indexOf('?'));
                                }else{
                                    database = urlValue.substring(urlValue.lastIndexOf('/')+1);
                                }
                                xmlMap.put(DATABASE, database);
                            }
                            xmlMap.put(attr.getNodeName(), attr.getNodeValue());
                        }
                    }
                }
            }

            NodeList entryNodeList = doc.getElementsByTagName(ENTRY);
            for(int i=0;i<entryNodeList.getLength();i++){
                Node node = entryNodeList.item(i);
                if(node.getNodeType()==Node.ELEMENT_NODE){
                    //如果元素名为entry，则解析属性key的值，并以键值对key-entry的形式保存
                    if(node.getNodeName()==DomParser.ENTRY){
                        NamedNodeMap namedNodeMap = node.getAttributes();
                        for(int j=0;j<namedNodeMap.getLength();j++){
                            Node attr = namedNodeMap.item(j);
                            xmlMap.put(attr.getNodeValue(), node.getTextContent());
                        }
                    }
                }
            }

            //数据库方言
            String url = xmlMap.get(URL);
            Database database = AbstractDatabase.newDatabase(Dialect.getDialectByUrl(url));


            /** 是否对该数据库下所有table生成代码，默认为false */
            if("true".equals(xmlMap.get(IS_ALL_TABLE))){
                List<String> tableNames = database.getTablesByDatabase(xmlMap);
                for(String tableName : tableNames){
                    Map<String, Object> tableMap = new HashMap<>();
                    tableMap.putAll(xmlMap);
                    tableMap.put("tableName", tableName);
                    /** 缺省值处理 */
                    handleDefaultValue(database, tableMap);
                    tables.add(tableMap);
                }
            }else{
                NodeList tableNodeList = doc.getElementsByTagName(TABLE);
                for(int i=0;i<tableNodeList.getLength();i++){
                    Node node = tableNodeList.item(i);
                    if(node.getNodeType()==Node.ELEMENT_NODE){
                        if(node.getNodeName()==DomParser.TABLE){
                            NamedNodeMap namedNodeMap = node.getAttributes();
                            Map<String, Object> tableMap = new HashMap<>();
                            tableMap.putAll(xmlMap);
                            for(int j=0;j<namedNodeMap.getLength();j++){
                                Node attr = namedNodeMap.item(j);
                                String nodeValue = attr.getNodeValue();
                                tableMap.put(attr.getNodeName(), nodeValue);
                                if(CLASS_NAME.equals(attr.getNodeName())){
                                    String injectClassNameValue = nodeValue.substring(0, 1).toLowerCase() + nodeValue.substring(1);
                                    tableMap.put(INJECT_CLASS_NAME, injectClassNameValue);
                                    tableMap.put(RESTFUL_CLASS_URL, SEPARATOR + injectClassNameValue);
                                }
                            }

                            /** 缺省值处理 */
                            handleDefaultValue(database, tableMap);
                            tables.add(tableMap);
                        }
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tables;
    }

    private static void handleDefaultValue(Database database, Map<String, Object> tableMap){
        //设置className缺省值
        if(!tableMap.containsKey(CLASS_NAME)){
            String tableName = (String)tableMap.get(TABLE_NAME);
            if(tableName==null || tableName.length() < 1){
                throw new RuntimeException("tableName未设置..");
            }
            String classNameValue = "";
            //tableName包含下划线
            if(tableName.length() > 1 && tableName.contains("_")){
                String[] tableNameParts = tableName.split("_");
                for(String tableNamePart : tableNameParts){
                    if(tableNamePart.length()>0){
                        classNameValue += tableNamePart.substring(0, 1).toUpperCase() + tableNamePart.substring(1);
                    }
                }
            }else{
                classNameValue = tableName.substring(0, 1).toUpperCase() + tableName.substring(1);
            }
            tableMap.put(CLASS_NAME, classNameValue);

            String injectClassNameValue = classNameValue.substring(0, 1).toLowerCase() + classNameValue.substring(1);
            tableMap.put(INJECT_CLASS_NAME, injectClassNameValue);
            tableMap.put(RESTFUL_CLASS_URL, SEPARATOR + injectClassNameValue);
        }

        //设置describe缺省值
        if(!tableMap.containsKey(DESCRIBE)){
            String describe = database.getTableCommentInfo(tableMap);
            tableMap.put("describe", describe);
        }
        /** 数据库处理 */
        List<Entity> entityList = database.getEntityObjList(tableMap);
        tableMap.put("entityList", entityList);
    }

}
